package no.hig.ekm.ircclient;

import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.prefs.Preferences;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import jerklib.Profile;

/**
 * The class responsible for the connectionDialog. Contains whats needed for
 * spawing the dialog window, and for calling the methods for connecting to the
 * server.
 * 
 * @author eigil, kristoffers, morten
 */
public class ConnectionDialog extends JInternalFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	// Static REsourceBundle, used to get text-stings in correct language.
	private static ResourceBundle text;

	// GUI-components.
	private JPanel mainPanel, networkMenuPanel, serverMenuPanel,
			editButtonPanel, connectButtonPanel, invisiblePanel,
			submitButtonPanel;
	private JButton addButton, editButton, deleteButton, sortButton,
			connectButton, btnClose;
	private JLabel nameLabel, nickLabel, nick2Label, serverLabel;
	private JTextField nameField, nickField, nickField2;
	private JCheckBox invisibleCB;
	private FlowLayout networkLayout, serverLayout, invisiblePanelLayout;
	private static JComboBox<String> networkList;
	private static JComboBox<String> serverList;
	private Server sServer = null;

	private GridBagLayout mainLayout;

	private boolean pendingChanges = false;

	static Preferences prefs;
	// All constant variables related to preferances
	private static final String CDXPOS = "cdXPos";
	private static final int CDXPOS_DEF = 15;
	private static final String CDYPOS = "cdYPos";
	private static final int CDYPOS_DEF = 15;
	private static final String CDNAME = "cdName";
	private static final String CDNAME_DEF = "Name";
	private static final String CDNICK = "cdNick";
	private static final String CDNICK_DEF = "Nick";
	private static final String CDNICK2 = "cdNick2";
	private static final String CDNICK2_DEF = "Nick2";
	private static final String CDSELNET = "cdSelNet"; // Last selected network
	private static final int CDSELNET_DEF = 0;
	private static final String CDSELSERV = "cdSelServ"; // Last selected server
	private static final int CDSELSERV_DEF = 0;

	/**
	 * Constructs the window, and sets it visible.
	 */
	public ConnectionDialog() {
		super(text.getString("connectionDialogTitle"), true, true, false);

		// Gets a hashmap with program preferences
		prefs = Preferences.userNodeForPackage(getClass());

		// Create all fields, buttons, etc.
		this.generate_layout();

		// Sets size and position for given window
		setSize(310, 320); // The size is constant, so no need to load it from
							// preferences

		// Store connection dialog location from preferences in local variables
		int cdXPos = prefs.getInt(CDXPOS, CDXPOS_DEF);
		int cdYPos = prefs.getInt(CDYPOS, CDYPOS_DEF);
		// Get the parent JDesktopPane dimensions
		int mainW = MainWindow.md.getWidth();
		int mainH = MainWindow.md.getHeight();
		//System.out.printf("DEBUG: Window size w=%d,h=%d\n", mainW, mainH);
		//System.out.printf("DEBUG: Window pos x=%d,y=%d\n", cdXPos, cdYPos);
		// Check whether the connection dialog location is outside the parents'
		// bounds
		if (cdXPos > mainW || cdYPos > mainH) {
			// Restore the default position
			cdXPos = CDXPOS_DEF;
			cdYPos = CDYPOS_DEF;
		}
		// Finally, position the dialog
		setLocation(cdXPos, cdYPos);

		getRootPane().setDefaultButton(connectButton);
		this.setResizable(false);
		this.setVisible(true);
		this.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);

	}

	/**
	 * Method to generate the layout in the ConnectionWindow
	 * 
	 */
	private void generate_layout() {
		// Local variables
		GridBagConstraints gbc = new GridBagConstraints();

		// Create the networkmenupanel
		networkMenuPanel = new JPanel();
		networkMenuPanel.setLayout(networkLayout = new FlowLayout());
		networkLayout.setVgap(0);
		networkList = new JComboBox<String>();
		networkList.setToolTipText(text
				.getString("connectionDialogChooseNetworkTooltip"));
		networkList.addItem(text.getString("connectionDialogChooseNetwork"));
		networkMenuPanel.add(new JLabel(text
				.getString("connectionDialogNetworkLabel")));
		networkMenuPanel.add(networkList);

		networkList.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				/* Gets the currently selected network */
				String selectedNetwork = networkList.getSelectedItem()
						.toString();
				/*
				 * If the selected network exists, add its servers to the server
				 * list
				 */
				int totServ = serverList.getItemCount();
				if (IniParser.exists(selectedNetwork)) {
					reloadServerList(selectedNetwork);
					totServ = serverList.getItemCount();
					// If there are no servers, add "Empty"
					if (totServ == 0)
						serverList.addItem("<Empty>");
				}

				// If the selected network is the same as in preferences, try to
				// select a server
				if (networkList.getSelectedIndex() == prefs.getInt(CDSELNET,
						CDSELNET_DEF)) {
					int selServ = prefs.getInt(CDSELSERV, CDSELSERV_DEF);
					if (totServ >= selServ) // Error handling
						serverList.setSelectedIndex(selServ);
				}
			}
		});

		// Create the servermenupanel
		serverMenuPanel = new JPanel();
		serverMenuPanel.setLayout(serverLayout = new FlowLayout());
		serverLayout.setVgap(0);
		serverList = new JComboBox<String>();
		serverList.setToolTipText(text
				.getString("connectionDialogChooseServerTooltip"));
		serverList.addItem(text.getString("connectionDialogChooseServer"));
		serverMenuPanel.add(new JLabel(text
				.getString("connectionDialogServerLabel")));
		serverMenuPanel.add(serverList);

		// Update the server URL label
		serverList.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				/* Gets the currently selected server */
				if (serverList.getItemCount() > 0) {
					try {
						getSelectedServer();
					} catch (NullPointerException npe) {
						System.err.println("Could not find selected server!");
					}
				}
			}
		});

		// Create the editButtonPanel
		editButtonPanel = new JPanel();
		editButtonPanel.setLayout(new GridLayout(4, 1));
		// Create the add-button, and add it to the panel
		addButton = new JButton(
				text.getString("connectionDialogEditButtonsAddLabel"));
		addButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				ArrayList<String> newValues = new ArrayList<String>();
				AddEditDialog aeDialog = new AddEditDialog(networkList
						.getSelectedItem().toString());
				newValues = aeDialog.getLastVals();

				// If the user clicked OK or exited without changing anything
				if (!newValues.isEmpty()) {
					// System.out.println(newValues);

					String nName = newValues.get(3);
					String sName = newValues.get(0);
					String sAddr = newValues.get(1);
					String sPort = newValues.get(2);

					if (IniParser.exists(nName)) {
						// If the given network name exists, add the server data
						// to it
						Network net = IniParser.find(nName);
						net.addServer(sName, sAddr, sPort);
						System.out
								.printf("DEBUG: Successfully added %s to an existing network %s",
										newValues, nName);
					} else {
						// We need to create a completely new network
						Network net = new Network(nName);
						net.addServer(sName, sAddr, sPort);
						IniParser.nets.add(net);
						networkList.addItem(nName);
						networkList.setSelectedItem(nName);
						// reload the server list with the new data

						System.out
								.println("The server has been successfully created!");

					}
					reloadServerList(nName);
					// ..and select the new server
					serverList.setSelectedItem(sName);
					pendingChanges = true;
				}
			}
		});
		addButton.setToolTipText(text
				.getString("connectionDialogEditButtonsAddTooltip"));
		editButtonPanel.add(addButton);
		// Create the add-button, and add it to the panel
		editButton = new JButton(
				text.getString("connectionDialogEditButtonsEditLabel"));

		editButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				ArrayList<String> newValues = new ArrayList<String>();
				AddEditDialog aeDialog;
				String nName = networkList.getSelectedItem().toString();
				String serverName = serverList.getSelectedItem().toString();
				// Try to edit a server
				try {
					sServer = IniParser.find(nName, serverName);
					// serverLabel.setText(sServer.getUrl());
					aeDialog = new AddEditDialog(serverName, sServer.getUrl(),
							sServer.getPorts(), nName);
					newValues = aeDialog.getLastVals();

					// If the user clicked OK or exited without changing
					// anything
					if (!newValues.isEmpty()) {
						System.out.println(newValues);
						sServer.setName(newValues.get(0));
						sServer.setUrl(newValues.get(1));
						sServer.setPorts(newValues.get(2));
						// Save the currently selected index
						int curInd = serverList.getSelectedIndex();
						// reload the server list with the new data
						reloadServerList(nName);
						// ..and select the previously selected server
						serverList.setSelectedIndex(curInd);
						System.out
								.println("The server has been successfully edited!");
						pendingChanges = true;
					}

				} catch (java.lang.NullPointerException npe) {
					System.err
							.println("ERROR: Select a Network and server first!");
				}
			}
		});

		editButton.setToolTipText(text
				.getString("connectionDialogEditButtonsEditTooltip"));
		editButtonPanel.add(editButton);
		// Create the add-button, and add it to the panel
		deleteButton = new JButton(
				text.getString("connectionDialogEditButtonsDeleteLabel"));
		deleteButton.setToolTipText(text
				.getString("connectionDialogEditButtonsDeleteTooltip"));
		deleteButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				/* Gets the currently selected server */
				if (serverList.getItemCount() > 0) {
					try {
						int dialogResult = JOptionPane
								.showConfirmDialog(
										null,
										"Are you sure you want to delete the selected server?",
										"Warning", JOptionPane.YES_NO_OPTION);
						if (dialogResult == JOptionPane.YES_OPTION) {
							String nName = networkList.getSelectedItem()
									.toString();
							String sName = serverList.getSelectedItem()
									.toString();
							Network net = IniParser.find(nName);
							if (net.removeServer(sName)) {
								serverList.removeItem(sName);
								if (!net.hasServers()
										&& (serverList.getItemCount() == 0))
									serverList.addItem("<Empty>");
								System.out
										.printf("The server '%s' has been successfully removed! \n",
												sName);
								pendingChanges = true;
							} else
								System.err
										.printf("The server '%s' was NOT successfully removed! \n",
												sName);
						}
					} catch (NullPointerException npe) {
						System.err.println("Could not find selected server!");
					}
				}
			}
		});

		editButtonPanel.add(deleteButton);
		// Create the add-button, and add it to the panel
		sortButton = new JButton(
				text.getString("connectionDialogEditButtonsSortLabel"));
		sortButton.setToolTipText(text
				.getString("connectionDialogEditButtonsSortTooltip"));
		editButtonPanel.add(sortButton);

		// Create the submitButtonPanel
		submitButtonPanel = new JPanel();
		submitButtonPanel.setLayout(new GridLayout(1, 3));
		// Create the add-button, and add it to the panel
		btnClose = new JButton(
				text.getString("connectionDialogSubmitButtonsCloseLabel"));

		btnClose.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				IniParser.saveData();
				pendingChanges = false;
				savePrefs();
				dispose();
				Main.win.setDefaultCloseOperation(EXIT_ON_CLOSE);
			}
		});

		// okButton.setToolTipText(text.getString("connectionDialogSubmitButtonsOkTooltip"));
		submitButtonPanel.add(btnClose);

		// Create the connectbutton
		GridBagConstraints gridBagConstraints = new GridBagConstraints();
		connectButtonPanel = new JPanel();
		connectButtonPanel.setLayout(new GridBagLayout());

		serverLabel = new JLabel("Choose a server");
		connectButtonPanel.add(serverLabel, gridBagConstraints);
		gridBagConstraints.gridx = 0;
		gridBagConstraints.gridy = 1;
		connectButton = new JButton(
				text.getString("connectionDialogConnectButtonLabel"));
		connectButton.setToolTipText(text
				.getString("connectionDialogConnectButtonTooltip"));
		connectButtonPanel.add(connectButton, gridBagConstraints);

		connectButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				// If a server has been selected try to connect to it
				if (sServer != null) {
					setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
					Main.cm.connectToServer(sServer.getUrl(), sServer
							.getPorts(), new Profile(nameField.getText(),
							nickField.getText(), nickField2.getText(), ""),
							false);
				} else {
					System.err.println("Please select a server first!");
				}
			}
		});

		// Create the invisiblePanel
		invisiblePanel = new JPanel();
		invisiblePanel.setLayout(invisiblePanelLayout = new FlowLayout());
		invisiblePanelLayout.setAlignment(FlowLayout.LEFT);
		invisibleCB = new JCheckBox(
				text.getString("connectionDialogInvisibleLabel"));
		invisibleCB.setToolTipText(text
				.getString("connectionDialogInvisibleTooltip"));
		invisiblePanel.add(invisibleCB);

		// Create the main layout
		mainPanel = new JPanel();
		mainPanel.setLayout(mainLayout = new GridBagLayout());
		gbc.fill = GridBagConstraints.NONE;

		// Add the networkMenu to the main layout
		gbc.insets = new Insets(2, 2, 2, 2);
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.gridwidth = 2;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.EAST;
		mainLayout.setConstraints(networkMenuPanel, gbc);
		mainPanel.add(networkMenuPanel);

		// Add the serverMenu to the main layout
		gbc.gridx = 0;
		gbc.gridy = 1;
		gbc.gridwidth = 2;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.EAST;
		mainLayout.setConstraints(serverMenuPanel, gbc);
		mainPanel.add(serverMenuPanel);

		// Add the editbuttons to the main layout
		gbc.gridx = 2;
		gbc.gridy = 0;
		gbc.gridwidth = 1;
		gbc.gridheight = 3;
		gbc.anchor = GridBagConstraints.CENTER;
		mainLayout.setConstraints(editButtonPanel, gbc);
		mainPanel.add(editButtonPanel);

		// Add the connectbutton to the main layout
		gbc.gridx = 0;
		gbc.gridy = 2;
		gbc.gridwidth = 2;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.CENTER;
		mainLayout.setConstraints(connectButtonPanel, gbc);
		mainPanel.add(connectButtonPanel);

		// Add the Textlabels to the main layout
		gbc.gridx = 0;
		gbc.gridy = 3;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.EAST;
		nameLabel = new JLabel(text.getString("connectionDialogNameLabel"));
		mainLayout.setConstraints(nameLabel, gbc);
		mainPanel.add(nameLabel);
		// gbc.gridy = 4;
		// emailLabel = new
		// JLabel(text.getString("connectionDialogEmailLabel"));
		// mainLayout.setConstraints(emailLabel, gbc);
		// mainPanel.add(emailLabel);
		gbc.gridy = 4;
		nickLabel = new JLabel(text.getString("connectionDialogNickLabel"));
		mainLayout.setConstraints(nickLabel, gbc);
		mainPanel.add(nickLabel);
		gbc.gridy = 5;
		nick2Label = new JLabel(text.getString("connectionDialogNick2Label"));
		mainLayout.setConstraints(nick2Label, gbc);
		mainPanel.add(nick2Label);

		// Add the textfields to the main layout
		gbc.gridx = 1;
		gbc.gridy = 3;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.CENTER;
		nameField = new JTextField(prefs.get(CDNAME, CDNAME_DEF), 12);
		nameField.setToolTipText(text.getString("connectionDialogNameTooltip"));
		mainLayout.setConstraints(nameField, gbc);
		mainPanel.add(nameField);
		// gbc.gridy = 4;
		// nameField = new JTextField ("", 12);
		// nameField.setToolTipText(text.getString("connectionDialogEmailTooltip"));
		// mainLayout.setConstraints(nameField, gbc);
		// mainPanel.add(nameField);
		gbc.gridy = 4;
		gbc.anchor = GridBagConstraints.WEST;
		nickField = new JTextField(prefs.get(CDNICK, CDNICK_DEF), 12);
		nickField.setToolTipText(text.getString("connectionDialogNickTooltip"));
		mainLayout.setConstraints(nickField, gbc);
		mainPanel.add(nickField);
		gbc.gridy = 5;
		nickField2 = new JTextField(prefs.get(CDNICK2, CDNICK2_DEF), 12);
		nickField2.setToolTipText(text
				.getString("connectionDialogNick2Tooltip"));
		mainLayout.setConstraints(nickField2, gbc);
		mainPanel.add(nickField2);

		// Add the invisiblepanel to the main layout
		gbc.gridx = 1;
		gbc.gridy = 6;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.WEST;
		mainLayout.setConstraints(invisiblePanel, gbc);
		mainPanel.add(invisiblePanel);

		// Add the submitbuttons to the main layout
		gbc.gridx = 0;
		gbc.gridy = 7;
		gbc.gridwidth = 3;
		gbc.gridheight = 1;
		gbc.anchor = GridBagConstraints.CENTER;
		mainLayout.setConstraints(submitButtonPanel, gbc);
		mainPanel.add(submitButtonPanel);

		this.add(mainPanel);

		addInternalFrameListener(new javax.swing.event.InternalFrameListener() {
			public void internalFrameActivated(
					javax.swing.event.InternalFrameEvent evt) {
			}

			public void internalFrameClosed(
					javax.swing.event.InternalFrameEvent evt) {
			}

			public void internalFrameClosing(
					javax.swing.event.InternalFrameEvent evt) {
				savePrefs();
				// Check whether the local file has been created
				if (!IniParser.usingLocalFile())
					pendingChanges = true;

				if (pendingChanges) {
					int confirmed = JOptionPane.showConfirmDialog(null, 
						text.getString("ConnectionDialogSCDIFC"),
						text.getString("ConnectionDialogSCDIFCTitle"), 
						JOptionPane.YES_NO_OPTION);
					if (confirmed == JOptionPane.YES_OPTION) {
						dispose();
						Main.win.setDefaultCloseOperation(EXIT_ON_CLOSE);
					} else if (MainWindow.closing)
						Main.win.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
				} else
					dispose();

			}

			/* (non-Javadoc)
			 * @see javax.swing.event.InternalFrameListener#internalFrameDeactivated(javax.swing.event.InternalFrameEvent)
			 */
			public void internalFrameDeactivated(
					javax.swing.event.InternalFrameEvent evt) {
			}

			/* (non-Javadoc)
			 * @see javax.swing.event.InternalFrameListener#internalFrameDeiconified(javax.swing.event.InternalFrameEvent)
			 */
			public void internalFrameDeiconified(
					javax.swing.event.InternalFrameEvent evt) {
			}

			/* (non-Javadoc)
			 * @see javax.swing.event.InternalFrameListener#internalFrameIconified(javax.swing.event.InternalFrameEvent)
			 */
			public void internalFrameIconified(
					javax.swing.event.InternalFrameEvent evt) {
			}

			/* (non-Javadoc)
			 * @see javax.swing.event.InternalFrameListener#internalFrameOpened(javax.swing.event.InternalFrameEvent)
			 */
			public void internalFrameOpened(
					javax.swing.event.InternalFrameEvent evt) {
			}
		});

	}
	
	/**
	 * Saves preferences
	 */
	private void savePrefs() {
		Point p = getLocation();
		// Save preferences before closing the window
		prefs.putInt(CDXPOS, p.x);
		prefs.putInt(CDYPOS, p.y);
		prefs.putInt(CDSELNET, networkList.getSelectedIndex());
		prefs.putInt(CDSELSERV, serverList.getSelectedIndex());
		prefs.put(CDNAME, nameField.getText());
		prefs.put(CDNICK, nickField.getText());
		prefs.put(CDNICK2, nickField2.getText());

	}

	/**
	 * Reloads a list of servers for a given network
	 * 
	 * @param network
	 */
	private void reloadServerList(String network) {
		serverList.removeAllItems();
		// System.out.println(IniParser.find(selectedNetwork).getServers().size());
		int i = 0;
		for (Server s : IniParser.find(network).getServers()) {
			i++;
			serverList.addItem(s.getName());
		}
		System.out.printf("Added %d servers\n", i);
	}

	/**
	 * Sets the server URL label
	 */
	private void getSelectedServer() {
		serverLabel.setText("");
		String selectedNetwork = networkList.getSelectedItem().toString();
		String serverName = serverList.getSelectedItem().toString();
		sServer = IniParser.find(selectedNetwork, serverName);
		serverLabel.setText(sServer.getUrl());
	}

	/**
	 * @param networkList
	 *            the networkList to set
	 */
	public static void setNetworkList(ArrayList<Network> arr) {
		for (Network n : arr) {
			networkList.addItem(n.getName());
		}
		int selNet = prefs.getInt(CDSELNET, CDSELNET_DEF);

		if (networkList.getItemCount() >= selNet)
			networkList.setSelectedIndex(selNet);
	}

	public static void setMessages(ResourceBundle messages) {
		ConnectionDialog.text = messages;
	}

}
